package controlSoftware.GUI;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import controlSoftware.DataProcess.SysModel;
import controlSoftware.UserThread.UserPool;
import controlSoftware.UserThread.UserThread;

import javax.swing.JMenuItem;
import controlSoftware.GUI.Map;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import controlSoftware.MockDataIn.*;

public class mainUI{
	
	/**
	 * UI variable declaration
	 */
	//TODO: change all to private and clean up initialization structure
	
	public JFrame frame;

	public static Canvas gridCanvas;
	public static Canvas mainCanvas;
	public static Canvas subCanvas;
	public static JPanel topCanvas;
	
	public static JLabel userListPanel;
	public static JButton startButton;
	public static JButton pauseButton;
	public static JButton stopButton;
	public static JButton playbackButton;
	
	// Map Panel
	public static JSlider mapScaleSlider;
	private static final int mapRatioMin = 50;
	private static final int mapRatioMax = 300;
	private JLabel label_ratio;
	private JLabel label_unit;
	public JTextField mapRatio;
	public String filePath;
	
	public static JLabel imgicon;
	public static JPanel userPanel;
	public static JLayeredPane layerPanel;
	public JList userList;
	public static DefaultListModel listModel;
	
	//Specify the look and feel to use. - null (use the default), "Metal", "System", "Motif", "GTK+"
    final static String LOOKANDFEEL = null;

    public static Map mMap;
	public static final int canvas_width = 600;
	public static final int canvas_height = 500;
	public static boolean usingMockDataFlag = true;
	static JPanel mainPane;
	JCheckBox recordSession;
	public static boolean isRecording = false;

	/**
	 * User Pool Definition
	 */
	public static UserPool userPool = new UserPool();
	public static MapRenderer mapRenderer = new MapRenderer();

	private Color highlight;
	static JMenuBar menubar;
	final JMenuItem fileItem1;
	final JMenuItem fileItem2;
	final JMenuItem fileItem3;
	final JMenuItem fileItem4;

	/**
	 * Launch the application.
	 */
	public static void main(String args[]) {

		//Schedule a job for the event-dispatching thread:
        //create the application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
            	initGUI();
            }
        });
	}

	
	//public final ImageIcon default_icon = new ImageIcon("img/image_icon.png");
	/**
	 * Create the application.
	 */
	public mainUI() {
		
		//*********** Canvas *******************
		
		layerPanel = new JLayeredPane();
		layerPanel.setPreferredSize(new Dimension(canvas_width, canvas_height));
	
		// Main canvas for map rendering
		mainCanvas = new Canvas();
		mainCanvas.setBounds(0, 0, canvas_width, canvas_height);	
		mainCanvas.setBackground(Color.white);
		

		layerPanel.setOpaque(false);
		//layerPanel.add(mainCanvas, JLayeredPane.DEFAULT_LAYER);
		layerPanel.add(mainCanvas, new Integer(10));
		
		// Sub canvas
		subCanvas = new Canvas();
		subCanvas.setBounds(0, canvas_height+30, canvas_width, 30);
		subCanvas.setBackground(Color.white);
		
		JPanel canvasPanel = new JPanel(new BorderLayout());
		canvasPanel.add(layerPanel, BorderLayout.NORTH);
		canvasPanel.add(subCanvas,BorderLayout.SOUTH);
		//************** Map ****************
		
		final JPanel mapPanel = new JPanel (new BorderLayout());
		//mapPanel.setLayout(new BoxLayout(mapPanel, BoxLayout.PAGE_AXIS));
		mapPanel.setOpaque(true);
		mapPanel.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder("Map Setting"),
                BorderFactory.createEmptyBorder(5,5,5,5)));
		
		label_ratio = new JLabel("Display Ratio:          ");
		label_unit = new JLabel(" px/m");
		
		mapRatio = new JTextField(2);	
		mapRatio.setEnabled(false);
		mapRatio.setText(String.valueOf(mapRatioMax));
		
		mapScaleSlider = new JSlider();
		mapScaleSlider.setMinimum(mapRatioMin);
		mapScaleSlider.setMaximum(mapRatioMax);
		mapScaleSlider.setMajorTickSpacing(50);
		mapScaleSlider.setMinorTickSpacing(25);
		mapScaleSlider.setPaintTicks(true);
		mapScaleSlider.setPaintTrack(true);
		mapScaleSlider.setValue(mapRatioMax);
		mapScaleSlider.setPaintLabels(true);
		mapScaleSlider.setEnabled(false);
		
		/** Control events for the slider **/
		mapScaleSlider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
            	int value = Integer.valueOf(mapScaleSlider.getValue());
            	
            	// avoid 0 case
            	if (value == 0)
            		mapScaleSlider.setValue(1);
 
            	mapRatio.setText(String.valueOf(value));
            	mMap.renderMap();
            }
        });

		mapRatio.addActionListener(new ActionListener() {    
            @Override
            public void actionPerformed(ActionEvent e) {
                try
                {
                	int value = Integer.parseInt(mapRatio.getText());
                	if (value == 0)
                		value = 1;
                	mapScaleSlider.setValue(value);
                }
                catch(Exception ex)
                {
                	JOptionPane.showMessageDialog(mapPanel, "ERROR: Please select an integer value between " + (int)(mapRatioMin + 1) + " and " + mapRatioMax + ".");
                }
            }
        });

		mapPanel.add(label_ratio, BorderLayout.LINE_START);
		mapPanel.add(mapRatio, BorderLayout.CENTER);
		mapPanel.add(label_unit, BorderLayout.LINE_END);
		mapPanel.add(mapScaleSlider, BorderLayout.PAGE_END);
		
		//************** User ****************
		
		userPanel = new JPanel (new BorderLayout());
		//userPanel.setBackground(Color.LIGHT_GRAY);
		userPanel.setOpaque(true);
		userPanel.getFont();
		userPanel.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder("Active Users"),
                BorderFactory.createEmptyBorder(5,5,5,5)));
		
		listModel = new DefaultListModel();
		userList = new JList(listModel);
		userList.setCellRenderer(new CustomListRenderer());
	
		userPanel.add(userList);
	
		
		//************** Info ****************
		
		JPanel infoPane = new JPanel();
		infoPane.setLayout(new BorderLayout());
		infoPane.setOpaque(true);

		//mapPanel.setBorder(new EmptyBorder(0 ,0, 0, 0));

		infoPane.add(mapPanel, BorderLayout.NORTH);
		infoPane.add(userPanel);
		infoPane.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));

		//************** Control ****************
		
		JPanel controlPane = new JPanel(new FlowLayout());
		controlPane.setOpaque(true);
		controlPane.setLayout(new FlowLayout(FlowLayout.LEFT));
		controlPane.setBorder(BorderFactory.createEmptyBorder(12, 0, 0, 0));
		
		startButton = new JButton("Start");
		startButton.setEnabled(true);
		startButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				startButton.setEnabled(false);
				stopButton.setEnabled(true);
				playbackButton.setEnabled(false);
				
				fileItem1.setEnabled(false);
				fileItem2.setEnabled(true);
				fileItem3.setEnabled(false);
				
				start();
			}
		});

		stopButton = new JButton("Stop");
		stopButton.setEnabled(false);
		stopButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				stopButton.setEnabled(false);
				startButton.setEnabled(true);
				playbackButton.setEnabled(true);
				
				fileItem1.setEnabled(false);
				fileItem2.setEnabled(true);
				fileItem3.setEnabled(true);
				
				stop();
				
			}
		});
		
		playbackButton = new JButton("Playback");
		playbackButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				startButton.setEnabled(false);
				stopButton.setEnabled(true);
				playbackButton.setEnabled(false);
				
				fileItem1.setEnabled(false);
				fileItem2.setEnabled(true);
				fileItem3.setEnabled(false);
				
				playback();			
			}
		});
		recordSession = new JCheckBox("Record");
		recordSession.setSelected(false);
		recordSession.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				if (recordSession.isSelected())
					isRecording = true;
				else
					isRecording = false;
				
				System.out.println(isRecording);
			}
		});

		controlPane.add(startButton);
		controlPane.add(stopButton);
		controlPane.add(playbackButton);
		controlPane.add(recordSession);
		
		//************** Menu **************
		menubar = new JMenuBar();
		menubar.setBackground(Color.WHITE);
		menubar.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
		JMenu filemenu = new JMenu("File");
		//filemenu.setBackground(Color.GRAY);
		JMenu editmenu = new JMenu("Edit");
		//editmenu.setBackground(Color.GRAY);
	
		fileItem1 = new JMenuItem("Start");
		fileItem2 = new JMenuItem("Stop");
		fileItem3 = new JMenuItem("Playback");
		fileItem4 = new JMenuItem("Exit");
		
		fileItem1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				startButton.setEnabled(false);
				stopButton.setEnabled(true);
				playbackButton.setEnabled(false);
				
				fileItem1.setEnabled(false);
				fileItem2.setEnabled(true);
				fileItem3.setEnabled(false);
				
				start();
			}
		});
		
		/* Reset */
		fileItem2.setEnabled(false);
		fileItem2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				startButton.setEnabled(true);
				stopButton.setEnabled(false);
				playbackButton.setEnabled(true);
				
				fileItem1.setEnabled(true);
				fileItem2.setEnabled(false);
				fileItem3.setEnabled(true);
				
				stop();
			}
		});
		
		/* Playback */
		fileItem3.setEnabled(true);
		fileItem3.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				playback();		
			}
		});
		
		/* Exit */
		fileItem4.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				System.exit(0);
			}
		});
		
		filemenu.add(fileItem4);
		editmenu.add(fileItem1);
		editmenu.add(fileItem2);
		editmenu.add(fileItem3);
		menubar.add(filemenu);
		menubar.add(editmenu);
		//menubar.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));

		//************** Title ****************
		
		JPanel titlePane = new JPanel(new BorderLayout());
		titlePane.setOpaque(true);
		String pathTitle = "img/titleimage.png";
		JLabel imageTitle = new JLabel(new ImageIcon(pathTitle));
		
		//titlePane.add(menubar, BorderLayout.PAGE_START);
		//titlePane.add(imageTitle,BorderLayout.WEST);
		titlePane.add(controlPane);	
		titlePane.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
		titlePane.setBorder(BorderFactory.createTitledBorder(""));
		
		
		//************** Display ****************
		
		JPanel displayPane = new JPanel (new BorderLayout());
		displayPane.setOpaque(true);
		
		displayPane.add(canvasPanel, BorderLayout.WEST);
		displayPane.add(infoPane, BorderLayout.EAST);
		//controlPane.add(sessionPanel, BorderLayout.PAGE_END);
		//******************************
		
		mainPane = new JPanel(new BorderLayout());
		mainPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		mainPane.add(titlePane, BorderLayout.NORTH);
		mainPane.add(displayPane, BorderLayout.WEST);

	}


	/**
	 * Initialize the contents of the frame.
	 */
	private static void initGUI() {
		
        //Set the look and feel.
        //initLookAndFeel(); TODOOOO
        
		// create and set up window
        JFrame frame = new JFrame();
		frame.setBounds(0, 0, 800, 702);
		frame.setTitle("Personal Geo-positioning System");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setResizable(false);
		frame.getContentPane().setLayout(new FlowLayout());
		
		// create and setup contents
		
		mainUI app = new mainUI();
		mainUI.mainPane.setOpaque(true);
		frame.setContentPane(app.mainPane);
		frame.setJMenuBar(menubar);
		
		frame.pack();
		frame.setVisible(true);
	}
/* COPIED THIS< MIGHT USE LATER	
	private static void initLookAndFeel() {
        String lookAndFeel = null;

        if (LOOKANDFEEL != null) {
            if (LOOKANDFEEL.equals("Metal")) {
                lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
            } else if (LOOKANDFEEL.equals("System")) {
                lookAndFeel = UIManager.getSystemLookAndFeelClassName();
            } else if (LOOKANDFEEL.equals("Motif")) {
                lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
            } else if (LOOKANDFEEL.equals("GTK+")) { //new in 1.4.2
                lookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
            } else {
                System.err.println("Unexpected value of LOOKANDFEEL specified: "
                                   + LOOKANDFEEL);
                lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
            }

            try {
                UIManager.setLookAndFeel(lookAndFeel);
            } catch (ClassNotFoundException e) {
                System.err.println("Couldn't find class for specified look and feel:"
                                   + lookAndFeel);
                System.err.println("Did you include the L&F library in the class path?");
                System.err.println("Using the default look and feel.");
            } catch (UnsupportedLookAndFeelException e) {
                System.err.println("Can't use the specified look and feel ("
                                   + lookAndFeel
                                   + ") on this platform.");
                System.err.println("Using the default look and feel.");
            } catch (Exception e) {
                System.err.println("Couldn't get specified look and feel ("
                                   + lookAndFeel
                                   + "), for some reason.");
                System.err.println("Using the default look and feel.");
                e.printStackTrace();
            }
        }
	}*/
	
	
	
	/**
	 * Confirms with user that the recording function is desired
	 */
	public void start()
	{
		usingMockDataFlag = false;
		
		if (isRecording)	// play recorded data
		{
			Object[] options = {"Ok","Cancel"};
			
			int response = JOptionPane.showOptionDialog(null,
			"This session will be recorded. If this is not desired, select Cancel and uncheck" +
			" 'record session' checkbox in the control panel.",
			"Confirm recording",
			JOptionPane.YES_NO_OPTION,
			JOptionPane.PLAIN_MESSAGE,
			null,
			options,
			options[0]);
			
			switch (response) {
				
			case 0:
				// start real time tracking
				startTracking(null);
				break;
            case 1:
                break;
			}
							
		}
		else
		{
			// start real time tracking
			startTracking(null);
		}
		
	}

	/**
	 * Start the tracking process
	 * @param isRecording
	 */
    private void startTracking(String recordFilePath) {
		mMap = new Map("xml/map.xml");
		
		// update slider after parsing value, map rendered automatically afterwards
		mapRatio.setEnabled(true);
		mapScaleSlider.setEnabled(true);
		mMap.renderMap();

		
		if (usingMockDataFlag)
			UserThread.initThread(recordFilePath);
		else
			UserThread.initThread();
    }
    
	protected void playback() {

		if (isRecording)
		{
			Object[] options = {"Continue"};
			
			int response = JOptionPane.showOptionDialog(null,
			"Playback session cannot be recorded",
			"Alert",
			JOptionPane.YES_OPTION,
			JOptionPane.PLAIN_MESSAGE,
			null,
			options,
			options[0]);
			
			isRecording = false;
			this.recordSession.setSelected(false);
		}
		
		// prompt the user for record file
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.addChoosableFileFilter(new XMLFilter());
		fileChooser.setAcceptAllFileFilterUsed(false);
		
		// set the dir to current dir
		try {
			File f = new File(new File(".").getCanonicalPath());
			fileChooser.setCurrentDirectory(f);
		} catch (IOException e) {
			e.printStackTrace();
		}

		//FileFilter filter = new FileFilter();
		//fileChooser.setFileFilter();
		int returnVal = fileChooser.showOpenDialog(mainPane);
		
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File file = fileChooser.getSelectedFile();
			filePath = file.getAbsolutePath();
		
			System.out.println(filePath);
			usingMockDataFlag = true;
			startTracking(filePath);
		
		}
		else
		{
			stopButton.setEnabled(false);
			startButton.setEnabled(true);
			playbackButton.setEnabled(true);
			
			fileItem2.setEnabled(false);
			fileItem1.setEnabled(true);
			fileItem3.setEnabled(true);
		}
	
	}

	public static void stop() {		
		//stop map renderer thread
		UserThread.mapRenderThread.interrupt();
		
		// stop all the thread processes
		userPool.stop();
		
		/**
		 * clear up the userPool to remove all users
		 */
		
		for (int i = 0; i < userPool.size(); i ++)
		{
			// clean the icon off the map
			userPool.get(i).getDataProcessThread().getViewController().clean();
		}
		userPool.clear();
		listModel.clear();

		usingMockDataFlag = false;
	}

	public void Exit() {
		System.exit(0);
	}


	/** Returns an ImageIcon, or null if the path was invalid. */
    protected static ImageIcon createImageIcon(String path) {
        java.net.URL imgURL = mainUI.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }
}


